﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;

namespace Gmantis.Controls.DataGrid
{
    [StyleTypedProperty(Property = "CellStyle", StyleTargetType = typeof(DataGridCellPresenter)), 
    StyleTypedProperty(Property = "HeaderStyle", StyleTargetType = typeof(DataGridGroupColumnHeaderPresenter))]
    public abstract class DataGridColumn : DependencyObject, INotifyPropertyChanged
    {
        // Fields
        private bool _actualCanUserFilter = true;
        private bool _actualCanUserMove = true;
        private bool _actualCanUserResize = true;
        private Style _actualCellContentStyle;
        private Style _actualCellStyle;
        private object _actualGroupHeader;
        private Style _actualHeaderStyle;
        private double _actualMaxWidth = double.PositiveInfinity;
        private double _actualMinWidth;
        private IDataGridFilter _filter;
        private DataGridFilterState _filterState;
        private DataGridGroupState _groupState;
        private double? _maxWidth;
        private double? _minWidth;
        private DataGridSortState _sortState;
        private Visibility _visibility;
        private DataGridLength? _width;
        public static readonly DependencyProperty CanUserFilterProperty;
        public static readonly DependencyProperty CanUserGroupProperty;
        public static readonly DependencyProperty CanUserMoveProperty;
        public static readonly DependencyProperty CanUserResizeProperty;
        public static readonly DependencyProperty CanUserResizeRowsProperty;
        public static readonly DependencyProperty CanUserSortProperty;
        public static readonly DependencyProperty CellContentStyleProperty = DependencyProperty.Register("CellContentStyle", typeof(Style), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.OnCellContentStylePropertyChanged)));
        public static readonly DependencyProperty CellEditingContentStyleProperty = DependencyProperty.Register("CellEditingContentStyle", typeof(Style), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.Refresh)));
        public static readonly DependencyProperty CellStyleProperty = DependencyProperty.Register("CellStyle", typeof(Style), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.OnCellStylePropertyChanged)));
        public static readonly DependencyProperty EditOnSelectionProperty;
        public static readonly DependencyProperty FilterMemberPathProperty;
        public static readonly DependencyProperty GroupContentStyleProperty = DependencyProperty.Register("GroupContentStyle", typeof(Style), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.Refresh)));
        public static readonly DependencyProperty GroupHeaderProperty = DependencyProperty.Register("GroupHeader", typeof(object), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.OnGroupHeaderPropertyChanged)));
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.OnHeaderPropertyChanged)));
        public static readonly DependencyProperty HeaderStyleProperty = DependencyProperty.Register("HeaderStyle", typeof(Style), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.OnActualHeaderStylePropertyChanged)));
        public static readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.Register("HorizontalAlignment", typeof(HorizontalAlignment), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.Refresh)));
        public static readonly DependencyProperty IsReadOnlyProperty;
        public static readonly DependencyProperty IsSelectableProperty;
        public static readonly DependencyProperty MaxWidthProperty;
        public static readonly DependencyProperty MinWidthProperty;
        public static readonly DependencyProperty SortMemberPathProperty;
        public static readonly DependencyProperty TagProperty;
        public static readonly DependencyProperty VerticalAlignmentProperty = DependencyProperty.Register("VerticalAlignment", typeof(VerticalAlignment), typeof(DataGridColumn), new PropertyMetadata(new PropertyChangedCallback(DataGridColumn.Refresh)));
        public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register("Visibility", typeof(Visibility), typeof(DataGridColumn), new PropertyMetadata(Visibility.Visible, new PropertyChangedCallback(DataGridColumn.OnVisibilityPropertyChanged)));
        public static readonly DependencyProperty WidthProperty;

        // Events
        internal event EventHandler<PropertyChangingEventArgs<int>> DisplayIndexChanging;
        public event EventHandler<DataGridFilterLoadingEventArgs> FilterLoading;
        public event EventHandler<PropertyChangedEventArgs<string>> FilterMemberPathChanged;
        [Obsolete("Use FilterLoading instead.", true)]
        public event LoadingFilterEventHandler LoadingFilter;
        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler<PropertyChangedEventArgs<string>> SortMemberPathChanged;
        public event EventHandler<PropertyChangedEventArgs<Visibility>> VisibilityChanged;
        internal event EventHandler<PropertyChangingEventArgs<Visibility>> VisibilityChanging;
        public event EventHandler<PropertyChangedEventArgs<DataGridLength>> WidthChanged;

        // Methods
        static DataGridColumn()
        {
            MinWidthProperty = DependencyProperty.Register("MinWidth", typeof(double), typeof(DataGridColumn), new PropertyMetadata(0.0, delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                DataGridColumn column = d as DataGridColumn;
                column._minWidth = new double?((double)e.NewValue);
                column.UpdateActualMinWidth();
            }));
            MaxWidthProperty = DependencyProperty.Register("MaxWidth", typeof(double), typeof(DataGridColumn), new PropertyMetadata((double)1.0 / (double)0.0, delegate(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                DataGridColumn column = d as DataGridColumn;
                column._maxWidth = new double?((double)e.NewValue);
                column.UpdateActualMaxWidth();
            }));
            WidthProperty = DependencyProperty.Register("Width", typeof(DataGridLength), typeof(DataGridColumn), new PropertyMetadata(new DataGridLength(1.0, DataGridUnitType.AutoStar), new PropertyChangedCallback(DataGridColumn.OnWidthPropertyChanged)));
            EditOnSelectionProperty = DependencyProperty.Register("EditOnSelection", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(false));
            SortMemberPathProperty = DependencyProperty.Register("SortMemberPath", typeof(string), typeof(DataGridColumn), new PropertyMetadata("", (d, e) => ((DataGridColumn)d).OnSortMemberPathChanged((string)e.NewValue, (string)e.OldValue)));
            FilterMemberPathProperty = DependencyProperty.Register("FilterMemberPath", typeof(string), typeof(DataGridColumn), new PropertyMetadata("", (d, e) => ((DataGridColumn)d).OnFilterMemberPathChanged((string)e.NewValue, (string)e.OldValue)));
            CanUserSortProperty = DependencyProperty.Register("CanUserSort", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true));
            CanUserGroupProperty = DependencyProperty.Register("CanUserGroup", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true));
            CanUserFilterProperty = DependencyProperty.Register("CanUserFilter", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true, (d, e) => (d as DataGridColumn).UpdateActualCanUserFilter()));
            CanUserResizeProperty = DependencyProperty.Register("CanUserResize", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true, (d, e) => (d as DataGridColumn).UpdateActualCanUserResize()));
            CanUserResizeRowsProperty = DependencyProperty.Register("CanUserResizeRows", typeof(bool), typeof(DataGridColumn), null);
            CanUserMoveProperty = DependencyProperty.Register("CanUserMove", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true, (d, e) => (d as DataGridColumn).UpdateActualCanUserMove()));
            IsSelectableProperty = DependencyProperty.Register("IsSelectable", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(true));
            IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(DataGridColumn), new PropertyMetadata(false));
            TagProperty = DependencyProperty.Register("Tag", typeof(object), typeof(DataGridColumn), new PropertyMetadata(null));
        }

        protected DataGridColumn()
        {
            this.Initialize();
        }

        public abstract bool BeginEdit(FrameworkElement editingElement, RoutedEventArgs routedEventArgs);
        public virtual void BindCellContent(FrameworkElement cellContent, DataGridRow row)
        {
            cellContent.DataContext = row.DataItem;
        }

        protected internal virtual void BindColumnHeaderPresenter(DataGridColumnHeaderPresenter columnHeaderPresenter)
        {
        }

        public abstract void CancelCellEdit(FrameworkElement editingElement, object uneditedValue);
        public abstract FrameworkElement CreateCellContent(DataGridRow row);
        protected internal virtual DataGridColumnHeaderPresenter CreateColumnHeaderPresenter()
        {
            return new DataGridColumnHeaderPresenter();
        }

        internal DataGridGroupColumnHeaderPresenter CreateGroupColumnHeaderPresenter()
        {
            return new DataGridGroupColumnHeaderPresenter();
        }

        public virtual FrameworkElement CreateGroupContent()
        {
            TextBlock block = new TextBlock
            {
                TextTrimming = TextTrimming.WordEllipsis,
                VerticalAlignment = VerticalAlignment.Center
            };
            Binding binding = new Binding
            {
                Converter = this.GroupContentConverter,
                ConverterCulture = GetEquivalentCulture(this.DataGrid.Language)
            };
            block.SetBinding(TextBlock.TextProperty, binding);
            if (this.GroupContentStyle != null)
            {
                block.Style = this.GroupContentStyle;
                return block;
            }
            block.Margin = new Thickness(4.0);
            return block;
        }

        public abstract void EndEdit(FrameworkElement editingElement);
        public abstract object GetCellContentRecyclingKey(DataGridRow row);
        public abstract FrameworkElement GetCellEditingContent(DataGridRow row);
        internal Style GetCellPresenterStyle()
        {
            return (this._actualCellStyle ?? this.DataGrid.CellStyle);
        }

        public virtual string GetCellText(DataGridRow row)
        {
            FrameworkElement cellContent = this.CreateCellContent(row);
            this.BindCellContent(cellContent, row);
            string text = "";
            if (cellContent is TextBlock)
            {
                text = ((TextBlock)cellContent).Text;
            }
            else if (cellContent is CheckBox)
            {
                CheckBox box = cellContent as CheckBox;
                text = box.IsChecked.HasValue ? (box.IsChecked.Value ? "Yes" : "No") : "Undefined";
            }
            this.UnbindCellContent(cellContent, row);
            return text;
        }

        public virtual object GetCellValue(DataGridRow Row)
        {
            return null;
        }

        protected internal virtual object GetColumnHeaderPresenterRecyclingKey()
        {
            if ((this.Header != null) && !(this.Header is string))
            {
                return null;
            }
            return typeof(DataGridColumnHeaderPresenter);
        }

        internal Style GetColumnHeaderPresenterStyle()
        {
            if (this.ActualHeaderStyle != null)
            {
                return this.ActualHeaderStyle;
            }
            return this.DataGrid.ColumnHeaderStyle;
        }

        public virtual string GetColumnText()
        {
            if (this.Header is string)
            {
                return (string)this.Header;
            }
            if (this.Header is TextBlock)
            {
                return ((TextBlock)this.Header).Text;
            }
            if (!(this.Header is IList))
            {
                return "";
            }
            IList header = (IList)this.Header;
            StringBuilder builder = new StringBuilder();
            IEnumerator enumerator = header.GetEnumerator();
            if (enumerator.MoveNext())
            {
                while (true)
                {
                    builder.Append(enumerator.Current);
                    if (!enumerator.MoveNext())
                    {
                        break;
                    }
                    builder.Append(", ");
                }
            }
            return builder.ToString();
        }

        internal static CultureInfo GetEquivalentCulture(XmlLanguage lang)
        {
            CultureInfo currentCulture = CultureInfo.CurrentCulture;
            if (lang != null)
            {
                try
                {
                    currentCulture = new CultureInfo(lang.IetfLanguageTag);
                }
                catch
                {
                }
            }
            return currentCulture;
        }

        public virtual IDataGridFilter GetFilter()
        {
            return null;
        }

        internal Style GetGroupColumnHeaderPresenterStyle()
        {
            return this.DataGrid.GroupColumnHeaderStyle;
        }

        public virtual string GetGroupText(DataGridGroupRow groupRow)
        {
            FrameworkElement element = this.CreateGroupContent();
            element.DataContext = groupRow.DataItem;
            string text = "";
            if (element is TextBlock)
            {
                text = ((TextBlock)element).Text;
            }
            return text;
        }

        internal bool GetIsReadOnly()
        {
            if ((this.DataGrid == null) || (this.DataGrid.IsEditingRowsAllowed && this.DataGrid.CanUserEditRows))
            {
                return this.IsReadOnly;
            }
            return true;
        }

        internal ViewColumn GetViewColumn(bool forceCreate)
        {
            if (this.DataGrid != null)
            {
                return this.DataGrid.View.GetViewColumn(this, forceCreate);
            }
            return null;
        }

        internal DataGridLength GetWidth()
        {
            if (this._width.HasValue)
            {
                return this._width.Value;
            }
            if (this.DataGrid == null)
            {
                return new DataGridLength(1.0, DataGridUnitType.AutoStar);
            }
            return this.DataGrid.ColumnWidth;
        }

        private void Initialize()
        {
            this.HorizontalAlignment = HorizontalAlignment.Left;
            this.VerticalAlignment = VerticalAlignment.Center;
            this.IsAutoGenerated = false;
            this._sortState = new DataGridSortState(DataGridSortDirection.None, null);
            this._groupState = new DataGridGroupState(DataGridSortDirection.None, null);
        }

        private static void OnActualHeaderStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Refresh(d, e);
            (d as DataGridColumn)._actualHeaderStyle = (Style)e.NewValue;
        }

        private static void OnCellContentStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Refresh(d, e);
            (d as DataGridColumn)._actualCellContentStyle = (Style)e.NewValue;
        }

        private static void OnCellStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Refresh(d, e);
            (d as DataGridColumn)._actualCellStyle = (Style)e.NewValue;
        }

        private bool OnDisplayIndexChanging(int newValue, int oldValue)
        {
            PropertyChangingEventArgs<int> e = new PropertyChangingEventArgs<int>
            {
                NewValue = newValue,
                OldValue = oldValue
            };
            if (this.DisplayIndexChanging != null)
            {
                this.DisplayIndexChanging(this, e);
            }
            return !e.Cancel;
        }

        private void OnFilterLoading(DataGridFilterLoadingEventArgs e)
        {
            if (this.FilterLoading != null)
            {
                this.FilterLoading(this, e);
            }
        }

        private void OnFilterMemberPathChanged(string newValue, string oldValue)
        {
            if (this.FilterMemberPathChanged != null)
            {
                PropertyChangedEventArgs<string> e = new PropertyChangedEventArgs<string>
                {
                    NewValue = newValue,
                    OldValue = oldValue
                };
                this.FilterMemberPathChanged(this, e);
            }
        }

        private static void OnGroupHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Refresh(d, e);
            (d as DataGridColumn).UpdateActualGroupHeader();
        }

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Refresh(d, e);
            (d as DataGridColumn).UpdateActualGroupHeader();
        }

        private IDataGridFilter OnLoadingFilter()
        {
            if (this.LoadingFilter != null)
            {
                return this.LoadingFilter(this, new EventArgs());
            }
            return null;
        }

        protected void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(propertyName, false);
        }

        protected void OnPropertyChanged(string propertyName, bool refreshUIElements)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            if (refreshUIElements)
            {
                this.Refresh();
            }
        }

        private void OnSortMemberPathChanged(string newValue, string oldValue)
        {
            if (this.SortMemberPathChanged != null)
            {
                PropertyChangedEventArgs<string> e = new PropertyChangedEventArgs<string>
                {
                    NewValue = newValue,
                    OldValue = oldValue
                };
                this.SortMemberPathChanged(this, e);
            }
        }

        private void OnVisibilityChanged(Visibility newValue, Visibility oldValue)
        {
            if (this.VisibilityChanged != null)
            {
                PropertyChangedEventArgs<Visibility> e = new PropertyChangedEventArgs<Visibility>
                {
                    NewValue = newValue,
                    OldValue = oldValue
                };
                this.VisibilityChanged(this, e);
            }
        }

        private bool OnVisibilityChanging(Visibility newValue, Visibility oldValue)
        {
            PropertyChangingEventArgs<Visibility> e = new PropertyChangingEventArgs<Visibility>
            {
                NewValue = newValue,
                OldValue = oldValue
            };
            if (this.VisibilityChanging != null)
            {
                this.VisibilityChanging(this, e);
            }
            return !e.Cancel;
        }

        private static void OnVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as DataGridColumn).SetVisibility();
        }

        private void OnWidthChanged(DataGridLength newValue, DataGridLength oldValue)
        {
            if (this.WidthChanged != null)
            {
                PropertyChangedEventArgs<DataGridLength> e = new PropertyChangedEventArgs<DataGridLength>
                {
                    NewValue = newValue,
                    OldValue = oldValue
                };
                this.WidthChanged(this, e);
            }
        }

        private static void OnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as DataGridColumn).SetWidth();
        }

        public abstract object PrepareCellForEdit(FrameworkElement editingElement);
        protected void Refresh()
        {
            this.Refresh(true, true, true);
        }

        private static void Refresh(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as DataGridColumn).Refresh();
        }

        internal void Refresh(bool unloadCells = true, bool unloadColumnHeaders = true, bool unloadGroupRows = true)
        {
            if (this.ViewColumn != null)
            {
                this.ViewColumn.Unload(unloadCells, unloadColumnHeaders, unloadGroupRows);
            }
        }

        public virtual void SetCellValue(DataGridRow Row, object value)
        {
        }

        private void SetVisibility()
        {
            Visibility oldValue = this._visibility;
            Visibility visibility = this.Visibility;
            if ((oldValue != visibility) && this.OnVisibilityChanging(visibility, oldValue))
            {
                this._visibility = visibility;
                this.OnVisibilityChanged(visibility, oldValue);
            }
        }

        private void SetWidth()
        {
            DataGridLength width = this.Width;
            if (!this._width.HasValue || (this._width.Value != width))
            {
                DataGridLength? nullable = this._width;
                DataGridLength oldValue = nullable.HasValue ? nullable.GetValueOrDefault() : DataGridLength.Auto;
                this._width = new DataGridLength?(width);
                this.OnWidthChanged(this._width.Value, oldValue);
            }
        }

        public override string ToString()
        {
            return string.Format("(Index = {0}, DisplayIndex = {1}, Name = {2})", this.Index, this.DisplayIndex, this.Name);
        }

        public virtual void UnbindCellContent(FrameworkElement cellContent, DataGridRow row)
        {
            cellContent.DataContext = null;
        }

        protected internal virtual void UnbindColumnHeaderPresenter(DataGridColumnHeaderPresenter columnHeaderPresenter)
        {
        }

        internal void UpdateActualCanUserFilter()
        {
            this._actualCanUserFilter = ((((this.DataGrid == null) || (this.DataGrid.CanUserFilter && this.DataGrid.IsFilteringRowsAllowed)) && !string.IsNullOrEmpty(this.ActualFilterMemberPath)) && this.CanUserFilter) && (this.Filter != null);
            this.OnPropertyChanged("ActualCanUserFilter");
        }

        internal void UpdateActualCanUserMove()
        {
            this._actualCanUserMove = ((this.DataGrid == null) || this.DataGrid.CanUserReorderColumns) && this.CanUserMove;
            this.OnPropertyChanged("ActualCanUserMove");
        }

        internal void UpdateActualCanUserResize()
        {
            this._actualCanUserResize = ((this.DataGrid == null) || this.DataGrid.CanUserResizeColumns) && this.CanUserResize;
            this.OnPropertyChanged("ActualCanUserResize");
        }

        private void UpdateActualGroupHeader()
        {
            this._actualGroupHeader = this.GroupHeader ?? this.GetColumnText();
            this.OnPropertyChanged("ActualGroupHeader");
        }

        internal void UpdateActualMaxWidth()
        {
            this.Refresh();
            double? nullable = this._maxWidth;
            this._actualMaxWidth = nullable.HasValue ? nullable.GetValueOrDefault() : ((this.DataGrid != null) ? this.DataGrid.MaxColumnWidth : 0.0);
            this.OnPropertyChanged("ActualMaxWidth");
        }

        internal void UpdateActualMinWidth()
        {
            this.Refresh();
            double? nullable = this._minWidth;
            this._actualMinWidth = nullable.HasValue ? nullable.GetValueOrDefault() : ((this.DataGrid != null) ? this.DataGrid.MinColumnWidth : 0.0);
            this.OnPropertyChanged("ActualMinWidth");
        }

        internal void UpdateColumnWidth(DataGridLength oldValue)
        {
            if (!this._width.HasValue)
            {
                this.OnWidthChanged(this.GetWidth(), oldValue);
            }
        }

        internal void UpdateMouseOver()
        {
            this.OnPropertyChanged("IsMouseOver");
        }

        internal void UpdateSelection()
        {
            this.OnPropertyChanged("IsSelected");
        }

        // Properties
        public bool ActualCanUserFilter
        {
            get
            {
                return this._actualCanUserFilter;
            }
        }

        public bool ActualCanUserGroup
        {
            get
            {
                return ((((this.DataGrid == null) || (this.DataGrid.CanUserGroup && this.DataGrid.IsGroupingRowsAllowed)) && !string.IsNullOrEmpty(this.ActualSortMemberPath)) && this.CanUserGroup);
            }
        }

        internal bool ActualCanUserMove
        {
            get
            {
                return this._actualCanUserMove;
            }
        }

        public bool ActualCanUserResize
        {
            get
            {
                return this._actualCanUserResize;
            }
        }

        public bool ActualCanUserSort
        {
            get
            {
                return ((((this.DataGrid == null) || (this.DataGrid.CanUserSort && this.DataGrid.IsSortingRowsAllowed)) && !string.IsNullOrEmpty(this.ActualSortMemberPath)) && this.CanUserSort);
            }
        }

        internal Style ActualCellContentStyle
        {
            get
            {
                return this._actualCellContentStyle;
            }
        }

        public virtual string ActualFilterMemberPath
        {
            get
            {
                return this.FilterMemberPath;
            }
        }

        public object ActualGroupHeader
        {
            get
            {
                return this._actualGroupHeader;
            }
        }

        internal Style ActualHeaderStyle
        {
            get
            {
                return this._actualHeaderStyle;
            }
        }

        internal bool ActualIsEditable
        {
            get
            {
                return (this.IsEditable && !this.GetIsReadOnly());
            }
        }

        internal double ActualMaxWidth
        {
            get
            {
                return this._actualMaxWidth;
            }
        }

        internal double ActualMinWidth
        {
            get
            {
                return this._actualMinWidth;
            }
        }

        public virtual string ActualSortMemberPath
        {
            get
            {
                return this.SortMemberPath;
            }
        }

        public double ActualWidth
        {
            get
            {
                return this.ViewColumn.RenderWidth;
            }
        }

        internal int CalculatedDisplayIndex { get; set; }

        public bool CanUserFilter
        {
            get
            {
                return (bool)base.GetValue(CanUserFilterProperty);
            }
            set
            {
                base.SetValue(CanUserFilterProperty, value);
            }
        }

        public bool CanUserGroup
        {
            get
            {
                return (bool)base.GetValue(CanUserGroupProperty);
            }
            set
            {
                base.SetValue(CanUserGroupProperty, value);
            }
        }

        public bool CanUserMove
        {
            get
            {
                return (bool)base.GetValue(CanUserMoveProperty);
            }
            set
            {
                base.SetValue(CanUserMoveProperty, value);
            }
        }

        public bool CanUserResize
        {
            get
            {
                return (bool)base.GetValue(CanUserResizeProperty);
            }
            set
            {
                base.SetValue(CanUserResizeProperty, value);
            }
        }

        public bool CanUserResizeRows
        {
            get
            {
                return (bool)base.GetValue(CanUserResizeRowsProperty);
            }
            set
            {
                base.SetValue(CanUserResizeRowsProperty, value);
            }
        }

        public bool CanUserSort
        {
            get
            {
                return (bool)base.GetValue(CanUserSortProperty);
            }
            set
            {
                base.SetValue(CanUserSortProperty, value);
            }
        }

        public Style CellContentStyle
        {
            get
            {
                return (Style)base.GetValue(CellContentStyleProperty);
            }
            set
            {
                base.SetValue(CellContentStyleProperty, value);
            }
        }

        public Style CellEditingContentStyle
        {
            get
            {
                return (Style)base.GetValue(CellEditingContentStyleProperty);
            }
            set
            {
                base.SetValue(CellEditingContentStyleProperty, value);
            }
        }

        public Style CellStyle
        {
            get
            {
                return (Style)base.GetValue(CellStyleProperty);
            }
            set
            {
                base.SetValue(CellStyleProperty, value);
            }
        }

        public DataGrid DataGrid { get; internal set; }

        public int DisplayIndex
        {
            get
            {
                return this.CalculatedDisplayIndex;
            }
            set
            {
                if (this.DataGrid == null)
                {
                    throw new Exception("Setting DisplayIndex before adding the column to the collection isn't allowed.");
                }
                this.DataGrid.Model.MoveColumn(this, value);
            }
        }

        public bool EditOnSelection
        {
            get
            {
                return (bool)base.GetValue(EditOnSelectionProperty);
            }
            set
            {
                base.SetValue(EditOnSelectionProperty, value);
            }
        }

        public IDataGridFilter Filter
        {
            get
            {
                IDataGridFilter filter = this._filter ?? (this.OnLoadingFilter() ?? this.GetFilter());
                DataGridFilterLoadingEventArgs e = new DataGridFilterLoadingEventArgs(filter);
                this.OnFilterLoading(e);
                return e.Filter;
            }
            set
            {
                this._filter = value;
            }
        }

        public string FilterMemberPath
        {
            get
            {
                return (string)base.GetValue(FilterMemberPathProperty);
            }
            set
            {
                base.SetValue(FilterMemberPathProperty, value);
            }
        }

        public DataGridFilterState FilterState
        {
            get
            {
                return this._filterState;
            }
            internal set
            {
                this._filterState = value;
                this.OnPropertyChanged("FilterState");
            }
        }

        public virtual IValueConverter GroupContentConverter { get; set; }

        public Style GroupContentStyle
        {
            get
            {
                return (Style)base.GetValue(GroupContentStyleProperty);
            }
            set
            {
                base.SetValue(GroupContentStyleProperty, value);
            }
        }

        public virtual IValueConverter GroupConverter { get; set; }

        public object GroupHeader
        {
            get
            {
                return base.GetValue(GroupHeaderProperty);
            }
            set
            {
                base.SetValue(GroupHeaderProperty, value);
            }
        }

        public DataGridGroupState GroupState
        {
            get
            {
                return this._groupState;
            }
            set
            {
                this.InitialGroupState = value;
            }
        }

        [TypeConverter(typeof(DataGridColumnHeaderTypeConverter))]
        public object Header
        {
            get
            {
                return base.GetValue(HeaderProperty);
            }
            set
            {
                base.SetValue(HeaderProperty, value);
            }
        }

        public DataGridColumnHeaderPresenter HeaderPresenter
        {
            get
            {
                if (this.DataGrid == null)
                {
                    return null;
                }
                if (this.DataGrid.View == null)
                {
                    return null;
                }
                ViewColumn viewColumn = this.GetViewColumn(false);
                if (viewColumn == null)
                {
                    return null;
                }
                return viewColumn.GetHeaderPresenter(false);
            }
        }

        public Style HeaderStyle
        {
            get
            {
                return (Style)base.GetValue(HeaderStyleProperty);
            }
            set
            {
                base.SetValue(HeaderStyleProperty, value);
            }
        }

        public HorizontalAlignment HorizontalAlignment
        {
            get
            {
                return (HorizontalAlignment)base.GetValue(HorizontalAlignmentProperty);
            }
            set
            {
                base.SetValue(HorizontalAlignmentProperty, value);
            }
        }

        public double HorizontalOffset
        {
            get
            {
                if (((this.DataGrid != null) && (this.DataGrid.View != null)) && this.DataGrid.View.IsLoaded)
                {
                    return this.DataGrid.View.ScrollManager.GetScrollPositionFromColumnDisplayIndex(this.DisplayIndex);
                }
                return double.NaN;
            }
        }

        public int Index
        {
            get
            {
                if (this.DataGrid == null)
                {
                    return -1;
                }
                return this.DataGrid.Columns.IndexOf(this);
            }
        }

        internal DataGridGroupState InitialGroupState { get; set; }

        internal DataGridSortState InitialSortState { get; set; }

        public bool IsAutoGenerated { get; internal set; }

        public virtual bool IsEditable
        {
            get
            {
                return false;
            }
        }

        public bool IsFrozen
        {
            get
            {
                int displayIndex = this.DisplayIndex;
                return ((displayIndex >= 0) && (displayIndex < this.DataGrid.Model.FrozenColumnCount));
            }
        }

        public bool IsMouseOver
        {
            get
            {
                return this.DataGrid.View.IsMouseOverColumn(this);
            }
        }

        internal bool IsPrepared { get; set; }

        public bool IsReadOnly
        {
            get
            {
                return (bool)base.GetValue(IsReadOnlyProperty);
            }
            set
            {
                base.SetValue(IsReadOnlyProperty, value);
            }
        }

        public bool IsSelectable
        {
            get
            {
                return (bool)base.GetValue(IsSelectableProperty);
            }
            set
            {
                base.SetValue(IsSelectableProperty, value);
            }
        }

        public bool IsSelected
        {
            get
            {
                return this.DataGrid.Model.SelectionManager.SelectedColumns.Contains(this);
            }
        }

        public double MaxWidth
        {
            get
            {
                return (double)base.GetValue(MaxWidthProperty);
            }
            set
            {
                base.SetValue(MaxWidthProperty, value);
            }
        }

        public double MinWidth
        {
            get
            {
                return (double)base.GetValue(MinWidthProperty);
            }
            set
            {
                base.SetValue(MinWidthProperty, value);
            }
        }

        public virtual string Name { get; set; }

        public string SortMemberPath
        {
            get
            {
                return (string)base.GetValue(SortMemberPathProperty);
            }
            set
            {
                base.SetValue(SortMemberPathProperty, value);
            }
        }

        public DataGridSortState SortState
        {
            get
            {
                return this._sortState;
            }
            set
            {
                this.InitialSortState = value;
            }
        }

        public object Tag
        {
            get
            {
                return base.GetValue(TagProperty);
            }
            set
            {
                base.SetValue(TagProperty, value);
            }
        }

        public VerticalAlignment VerticalAlignment
        {
            get
            {
                return (VerticalAlignment)base.GetValue(VerticalAlignmentProperty);
            }
            set
            {
                base.SetValue(VerticalAlignmentProperty, value);
            }
        }

        internal ViewColumn ViewColumn
        {
            get
            {
                return this.GetViewColumn(true);
            }
        }

        public Visibility Visibility
        {
            get
            {
                return (Visibility)base.GetValue(VisibilityProperty);
            }
            set
            {
                base.SetValue(VisibilityProperty, value);
            }
        }

        public DataGridLength Width
        {
            get
            {
                return (DataGridLength)base.GetValue(WidthProperty);
            }
            set
            {
                base.SetValue(WidthProperty, value);
            }
        }
    }
}
